package util;

import java.lang.reflect.Field;

import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.ObjectFactory;

public class AopUtil {

	/**
	 * 获取 目标对象
	 * 
	 * @param proxy
	 *            代理对象
	 * @return
	 * @throws Exception
	 */
	public static Object getTarget(Object proxy) throws Exception {

		/*
		 * if(!AopUtils.isAopProxy(proxy)) { return proxy; } // jdk proxy
		 * if(AopUtils.isJdkDynamicProxy(proxy)) { return
		 * getJdkDynamicProxyTargetObject(proxy); } else { // cglib return
		 * getCglibProxyTargetObject(proxy); }
		 */
		Object target = null;

		try {
			target = getJdkDynamicProxyTargetObject(proxy);
		} catch (Throwable e) {
			//
		}
		if (target != null) {
			return target;
		}

		try {
			target = getCglibProxyTargetObject(proxy);
		} catch (Throwable e) {
			//
		}
		if (target != null) {
			return target;
		}

		return proxy;
	}

	private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
		h.setAccessible(true);
		Object dynamicAdvisedInterceptor = h.get(proxy);

		Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
		advised.setAccessible(true);

		Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();

		return target;
	}

	private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
		h.setAccessible(true);

		Object object = h.get(proxy);

		// private final ObjectFactory<?> objectFactory;

		Field objectFactoryField = object.getClass().getDeclaredField("objectFactory");
		objectFactoryField.setAccessible(true);

		Object objectFactoryObject = objectFactoryField.get(object);
		ObjectFactory objectFactory = (ObjectFactory) objectFactoryObject;

		return objectFactory.getObject();

		/*
		 * AopProxy aopProxy = (AopProxy) object;
		 * 
		 * Field advised = aopProxy.getClass().getDeclaredField("advised");
		 * advised.setAccessible(true);
		 * 
		 * Object target =
		 * ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget()
		 * ;
		 * 
		 * return target;
		 */
	}

	@SuppressWarnings({ "unchecked" })
	protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
		if (AopUtils.isJdkDynamicProxy(proxy)) {
			return (T) ((Advised) proxy).getTargetSource().getTarget();
		} else {
			// expected to be cglib proxy then, which is simply a specialized
			// class
			return (T) proxy;
		}
	}
}